//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
//
#include "windows.h"
#include "windowsx.h"
#include "wininet.h"
#include "commctrl.h"
#include "resource.h"
#include "ftpupdate.h"
#include "BldVer.h"
#include "pm.h"

#ifdef DEBUG

DBGPARAM dpCurSettings = {
    TEXT("FTPUpdate"), {
    TEXT("Init"),TEXT("Reg"),TEXT(""),TEXT(""),
    TEXT(""),TEXT(""),TEXT(""),TEXT(""),
    TEXT(""),TEXT(""),TEXT("Interface"),TEXT("Misc"),
    TEXT("Alloc"),    TEXT("Function"), TEXT("Warning"),  TEXT("Error") },
    0x0000FFFF
};
#else
DWORD   v_dwDebugFlag = 0xFFFF;     // Allow some retail debug zones.
#endif // DEBUG

#ifndef SHIP_BUILD
#ifndef DEBUG
#undef DEBUGZONE
#define DEBUGZONE(n)    (v_dwDebugFlag & (0x00000001<<n))
#endif

#define ZONE_INIT		DEBUGZONE(0)		// 0x0001
#define ZONE_REG		DEBUGZONE(1)		// 0x0002
//#define ZONE_???		DEBUGZONE(2)		// 0x0004
//#define ZONE_???		DEBUGZONE(3)		// 0x0008
//#define ZONE_???		DEBUGZONE(4)		// 0x0010
//#define ZONE_???		DEBUGZONE(5)		// 0x0020
//#define ZONE_???		DEBUGZONE(6)		// 0x0040
//#define ZONE_???		DEBUGZONE(7)		// 0x0080
//#define ZONE_???		DEBUGZONE(8)		// 0x0100
//#define ZONE_???      DEBUGZONE(9)		// 0x0200
#define ZONE_INTERFACE	DEBUGZONE(10)		// 0x0400
#define ZONE_MISC		DEBUGZONE(11)		// 0x0800
#define ZONE_ALLOC		DEBUGZONE(12)		// 0x1000
#define ZONE_FUNCTION	DEBUGZONE(13)		// 0x2000
#define ZONE_WARN		DEBUGZONE(14)		// 0x4000
#define ZONE_ERROR		DEBUGZONE(15)		// 0x8000
#endif

TCHAR       v_szAppName[MAX_PATH];

TCHAR       v_szServerName[MAX_PATH+1] = DEFAULT_FTP_SERVER;
TCHAR       v_szPathSpec[MAX_PATH+1] = DEFAULT_PATH_SPEC;
TCHAR       v_szSourceName[MAX_PATH+1] = DEFAULT_SRC_NAME;
TCHAR       v_szTempName[MAX_PATH+1];
TCHAR       v_szFinalName[MAX_PATH+1] = DEFAULT_DEST_NAME;
DWORD       v_dwFlags = DEFAULT_FLAGS;


HWND        v_hMainWnd;
HINSTANCE   v_hInstance;
BOOL        v_fDownloading;

DWORD       v_dwTotalSize;
DWORD       v_dwCurrent;
DWORD       v_fDownloadSuccess;

#define WM_DOWNLOAD_DONE        (WM_USER+1)
#define WM_DOWNLOAD_PROGRESS    (WM_USER+2)

typedef HINTERNET (WINAPI *PFN_InternetOpenW)(LPCWSTR lpszAgent, DWORD dwAccessType, LPCWSTR lpszProxy,
                                              LPCWSTR lpszProxyBypass, DWORD dwFlags);
typedef HINTERNET (WINAPI *PFN_InternetConnectW)(HINTERNET hInternet, LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
    LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext);
typedef HINTERNET (WINAPI *PFN_FtpFindFirstFileW)(HINTERNET hConnect, LPCWSTR lpszSearchFile,
    LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext);
typedef BOOL (WINAPI *PFN_InternetCloseHandle)(HINTERNET hInternet);
typedef BOOL (WINAPI *PFN_InternetFindNextFileW)(HINTERNET hFind, LPVOID lpvFindData);
typedef HINTERNET (WINAPI *PFN_FtpOpenFileW)(HINTERNET hConnect, LPCWSTR lpszFileName, DWORD dwAccess, DWORD dwFlags,
                                             DWORD_PTR dwContext);
typedef BOOL (WINAPI *PFN_InternetReadFile)(HINTERNET hFile, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead,
                                            LPDWORD lpdwNumberOfBytesRead);


PFN_InternetOpenW           pfnInternetOpenW;
PFN_InternetConnectW        pfnInternetConnectW;
PFN_FtpFindFirstFileW       pfnFtpFindFirstFileW;
PFN_InternetCloseHandle     pfnInternetCloseHandle;
PFN_InternetFindNextFileW   pfnInternetFindNextFileW;
PFN_FtpOpenFileW            pfnFtpOpenFileW;
PFN_InternetReadFile        pfnInternetReadFile;

BOOL
GetWinInetFuncs()
{
    HMODULE hModule;

    // We'll work with either Wininet or HTTPLITE
    if (NULL == (hModule = (HMODULE)LoadLibrary(TEXT("WININET.DLL")))) {
        if (NULL == (hModule = (HMODULE)LoadLibrary(TEXT("HTTPLITE.DLL")))) {
            return FALSE;
        }
    }

    pfnInternetOpenW = (PFN_InternetOpenW)GetProcAddress (hModule, TEXT("InternetOpenW"));
    pfnInternetConnectW = (PFN_InternetConnectW)GetProcAddress (hModule, TEXT("InternetConnectW"));
    pfnFtpFindFirstFileW = (PFN_FtpFindFirstFileW)GetProcAddress (hModule, TEXT("FtpFindFirstFileW"));
    pfnInternetCloseHandle = (PFN_InternetCloseHandle)GetProcAddress (hModule, TEXT("InternetCloseHandle"));
    pfnInternetFindNextFileW = (PFN_InternetFindNextFileW)GetProcAddress (hModule, TEXT("InternetFindNextFileW"));
    pfnFtpOpenFileW = (PFN_FtpOpenFileW)GetProcAddress (hModule, TEXT("FtpOpenFileW"));
    pfnInternetReadFile = (PFN_InternetReadFile)GetProcAddress (hModule, TEXT("InternetReadFile"));

    // Make sure we have all of the function pointers
    if ((NULL == pfnInternetOpenW) || (NULL == pfnInternetConnectW) || (NULL == pfnFtpFindFirstFileW) || (NULL == pfnInternetCloseHandle) ||
        (NULL == pfnInternetFindNextFileW) || (NULL == pfnFtpOpenFileW) || (NULL == pfnInternetReadFile)) {
        return FALSE;
    }

    // Don't bother free'ing the library since we need it installed to call and it will get freed at exit.
    return TRUE;
}


DWORD
DoFmtMsg (int MsgID, LPTSTR szDest, int cChars, ...)
{
    TCHAR   szFmt[MAX_PATH+1];
    va_list ArgList;

    va_start (ArgList, cChars);

    LoadString (v_hInstance, MsgID, szFmt,
                sizeof(szFmt)/sizeof(TCHAR));

    return FormatMessage (FORMAT_MESSAGE_FROM_STRING, szFmt, 0, 0, szDest, cChars, &ArgList);
}

void
ShowError (int MsgID, ...)
{
	va_list ArgList;
	TCHAR	szBuffer[256];
    TCHAR   szFmt[MAX_PATH+1];

	va_start (ArgList, MsgID);

    LoadString (v_hInstance, MsgID, szFmt, sizeof(szFmt)/sizeof(TCHAR));

    FormatMessage (FORMAT_MESSAGE_FROM_STRING, szFmt, 0, 0, szBuffer, sizeof(szBuffer)/sizeof(TCHAR), &ArgList);

    MessageBox (v_hMainWnd, szBuffer, v_szAppName, MB_OK | MB_TOPMOST | MB_ICONERROR);

    return;
}



DWORD
FTPGetFileSize ()
{
    HINTERNET hInet = NULL, hFTP = NULL, hOpen = NULL;
    WIN32_FIND_DATA FindFileData;

    memset ((char *)&FindFileData, 0, sizeof(FindFileData));
    
    hInet = pfnInternetOpenW (TEXT("WinCE FTP Update"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    if (NULL == hInet) {
        ShowError (IDS_ERR_INTERNET_OPEN, GetLastError());
        goto ErrorExit;
    }

    hFTP = pfnInternetConnectW (hInet, v_szServerName, INTERNET_INVALID_PORT_NUMBER, NULL, NULL,
                            INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
    if (NULL == hFTP) {
        ShowError (IDS_ERR_INTERNET_CONNECT, GetLastError());
        goto ErrorExit;
    }

    // Let's get some info on the file
    hOpen = pfnFtpFindFirstFileW (hFTP, v_szSourceName, &FindFileData, INTERNET_FLAG_NO_CACHE_WRITE, 0);

    if (NULL == hOpen) {
        ShowError (IDS_ERR_FTPFINDFIRST, GetLastError());
        goto ErrorExit;
    }

ErrorExit:    
    if (NULL != hOpen) {
        pfnInternetCloseHandle (hOpen);
    }
    
    if (NULL != hFTP) {
        pfnInternetCloseHandle (hFTP);
    }
    
    if (NULL != hInet) {
        pfnInternetCloseHandle (hInet);
    }
    
    return FindFileData.nFileSizeLow;
}

DWORD
FTPFillComboBox (LPVOID pvarg)
{
    HINTERNET hInet = NULL, hFTP = NULL, hOpen = NULL;
    WIN32_FIND_DATA FindFileData;
    LRESULT lResult;

    while ((CB_ERR != (lResult = ComboBox_DeleteString (GetDlgItem (v_hMainWnd, IDC_SOURCENAME), 0))) && lResult) {
        RETAILMSG (ZONE_WARN, (TEXT("deleted items\r\n")));
    }
    RETAILMSG (ZONE_WARN, (TEXT("Done deleting items\r\n")));
    
    memset ((char *)&FindFileData, 0, sizeof(FindFileData));
    
    hInet = pfnInternetOpenW (TEXT("WinCE FTP Update"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    if (NULL == hInet) {
        //ShowError (IDS_ERR_INTERNET_OPEN, GetLastError());
        goto ErrorExit;
    }

    hFTP = pfnInternetConnectW (hInet, v_szServerName, INTERNET_INVALID_PORT_NUMBER, NULL, NULL,
                            INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
    if (NULL == hFTP) {
        //ShowError (IDS_ERR_INTERNET_CONNECT, GetLastError());
        goto ErrorExit;
    }

    // Let's get some info on the file
    hOpen = pfnFtpFindFirstFileW (hFTP, v_szPathSpec, &FindFileData, INTERNET_FLAG_NO_CACHE_WRITE, 0);

    if (NULL == hOpen) {
        ShowError (IDS_ERR_FTPFINDFIRST, GetLastError());
        goto ErrorExit;
    }

    do {
        // Add this file to the combo box
        ComboBox_AddItemData (GetDlgItem (v_hMainWnd, IDC_SOURCENAME), FindFileData.cFileName);
        RETAILMSG (ZONE_WARN, (TEXT("Adding string '%s'\r\n"), FindFileData.cFileName));
        
    } while (pfnInternetFindNextFileW (hOpen, &FindFileData));

ErrorExit:    
    if (NULL != hOpen) {
        pfnInternetCloseHandle (hOpen);
    }
    
    if (NULL != hFTP) {
        pfnInternetCloseHandle (hFTP);
    }
    
    if (NULL != hInet) {
        pfnInternetCloseHandle (hInet);
    }
    
    return 0;
}

DWORD
FTPGetFile (LPVOID pvarg)
{
    HINTERNET hInet = NULL, hFTP = NULL, hOpen = NULL;
    HANDLE  hFile = INVALID_HANDLE_VALUE;
    PBYTE   pBuffer = NULL;
    DWORD   cBufferSize;
    BOOL    bRetVal = FALSE;
    DWORD   dwStartTick;
    WIN32_FIND_DATA FindFileData;

    // Try to allocate a 32K byte temporary buffer
    if (NULL == (pBuffer = (PBYTE)LocalAlloc (LMEM_FIXED, cBufferSize = 32*1024))) {
        // Couldn't allocate 32K, let's try 4K
        if (NULL == (pBuffer = (PBYTE)LocalAlloc (LMEM_FIXED, cBufferSize = 4*1024))) {
            // Couldn't do that either.  Let's just give up.
            ShowError (IDS_ERR_GETDISKFREESPACE, GetLastError());
            goto ErrorExit;
        }
    }
        

    v_dwTotalSize = 0;
    v_dwCurrent = 0;
    hInet = pfnInternetOpenW (TEXT("WinCE FTP Update"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    if (NULL == hInet) {
        ShowError (IDS_ERR_INTERNET_OPEN, GetLastError());
        goto ErrorExit;
    }

    hFTP = pfnInternetConnectW (hInet, v_szServerName, INTERNET_INVALID_PORT_NUMBER, NULL, NULL,
                            INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
    if (NULL == hFTP) {
        ShowError (IDS_ERR_INTERNET_CONNECT, GetLastError());
        goto ErrorExit;
    }

    // Let's get some info on the file
    hOpen = pfnFtpFindFirstFileW (hFTP, v_szSourceName, &FindFileData, INTERNET_FLAG_NO_CACHE_WRITE, 0);

    if (NULL == hOpen) {
        ShowError (IDS_ERR_FTPFINDFIRST, GetLastError());
        goto ErrorExit;
    }

    pfnInternetCloseHandle (hOpen);

    
    hOpen = pfnFtpOpenFileW (hFTP, v_szSourceName, GENERIC_READ,
                         FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD,
                         0);

    if (NULL == hOpen) {
        ShowError (IDS_ERR_FTPOPENFILE, GetLastError());
        goto ErrorExit;
    }

    hFile = CreateFile (v_szTempName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if (INVALID_HANDLE_VALUE == hFile) {
        ShowError (IDS_ERR_CREATEFILE, GetLastError());
        goto ErrorExit;
    }

    v_dwTotalSize = FindFileData.nFileSizeLow;
    dwStartTick = GetTickCount();
    while (1) {
        BOOL    bResult;
        DWORD   dwBytesRead, dwBytesWritten;

        bResult = pfnInternetReadFile (hOpen, pBuffer, cBufferSize, &dwBytesRead);

        if (FALSE == bResult) {
            ShowError (IDS_ERR_INTERNET_READ_FILE, GetLastError());
            break;
        }
        RETAILMSG (1, (TEXT("InternetReadFile: Asked for %d, read %d bytes\r\n"), cBufferSize, dwBytesRead));
        
//        _tprintf (TEXT("Read %d bytes"), dwBytesRead);
        v_dwCurrent += dwBytesRead;
        bResult = WriteFile (hFile, pBuffer, dwBytesRead, &dwBytesWritten, NULL);
        if (!bResult || (dwBytesWritten != dwBytesRead)) {
            RETAILMSG (ZONE_ERROR, (TEXT("Error %d(0x%08X) from WriteFile\r\n"), GetLastError(), GetLastError()));
            ShowError (IDS_ERR_WRITEFILE, GetLastError());
            break;
        }
        if (dwBytesRead != cBufferSize) {
            break;
        }
        SendMessage (v_hMainWnd, WM_DOWNLOAD_PROGRESS, 0, 0);

        // Make sure the system keeps alive.
        SystemIdleTimerReset();

    }

    if (v_dwCurrent == FindFileData.nFileSizeLow) {
        bRetVal = TRUE;
        v_fDownloadSuccess = TRUE;
    }

ErrorExit :
    PostMessage (v_hMainWnd, WM_DOWNLOAD_DONE, 0, 0);
    
    if (INVALID_HANDLE_VALUE != hFile) {
        CloseHandle (hFile);
    }
    if (NULL != hOpen) {
        pfnInternetCloseHandle (hOpen);
    }
    
    if (NULL != hFTP) {
        pfnInternetCloseHandle (hFTP);
    }
    
    if (NULL != hInet) {
        pfnInternetCloseHandle (hInet);
    }

    if (NULL != pBuffer) {
        LocalFree (pBuffer);
    }

    return bRetVal;
}

int
DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    ULARGE_INTEGER  uliFreeBytes, uliTotalBytes, uliTotalFree;
    TCHAR   szTemp[MAX_PATH+1];
    int     i;
    DWORD   dwImageSize;
    HANDLE  hThread;
    DWORD   dwThreadID;
    static  DWORD dwStartTick;
    DWORD   dwMin, dwSec;
    static  int OldPercent = -1;
    
	switch (message) {
    case WM_INITDIALOG :
        SetWindowText (GetDlgItem (hDlg, IDC_SERVER), v_szServerName);
        SetWindowText (GetDlgItem (hDlg, IDC_SOURCENAME), v_szSourceName);
        SetWindowText (GetDlgItem (hDlg, IDC_DESTNAME), v_szFinalName);
        SendMessage (GetDlgItem (hDlg, IDC_PROGRESS), PBM_SETRANGE, 0, MAKELPARAM (0,100));

        if (v_szPathSpec[0]) {
            // Start a thread to get the list of files
            hThread = CreateThread (NULL, 0, FTPFillComboBox, 0, 0, &dwThreadID);
            CloseHandle (hThread);
        }
        return TRUE;

    case WM_DOWNLOAD_PROGRESS :
        if (v_dwTotalSize) {
            i = v_dwCurrent*100/v_dwTotalSize;
        } else {
            i = 0;
        }
        // Only draw if percent has changed, reduce flicker.
        if (OldPercent != i) {
            OldPercent = i;
        } else {
            break;
        }
        if (i && (100 != i)) {
            dwThreadID = GetTickCount() - dwStartTick;
            // Figure out total time
            dwThreadID = dwThreadID*(100-i)/i;
            dwThreadID /= 1000;
            dwMin = dwThreadID / 60;
            dwSec = dwThreadID % 60;
        } else if (0 == i) {
            dwMin = 5;
            dwSec = 0;
        } else {
            dwMin = dwSec = 0;
        }
        
        
        DoFmtMsg (IDS_DOWNLOAD_PERCENT, szTemp, sizeof(szTemp)/sizeof(TCHAR), v_dwCurrent/1024, v_dwTotalSize/1024, i, dwMin, dwSec);
        SendMessage (GetDlgItem (hDlg, IDC_PROGRESS), PBM_SETPOS, i, 0);
        SetWindowText (GetDlgItem (hDlg, IDC_STATUS), szTemp);
        break;
        
    case WM_DOWNLOAD_DONE :
        if (v_dwTotalSize) {
            i = v_dwCurrent*100/v_dwTotalSize;
        } else {
            i = 0;
        }
        DoFmtMsg (IDS_DOWNLOAD_PERCENT, szTemp, sizeof(szTemp)/sizeof(TCHAR), v_dwCurrent/1024, v_dwTotalSize/1024, i, 0, 0);
        SetWindowText (GetDlgItem (hDlg, IDC_STATUS), szTemp);
        if (v_fDownloadSuccess) {
            if  (_tcscmp (v_szTempName, v_szFinalName)) {
                DeleteFile (v_szFinalName);
                MoveFile (v_szTempName, v_szFinalName);
            }
            
            // TODO: Spawn the applet to clear the reghive

            LoadString (v_hInstance, IDS_DOWNLOAD_DONE, szTemp,
                        sizeof(szTemp)/sizeof(TCHAR));
            MessageBox (hDlg, szTemp, v_szAppName, MB_OK|MB_TOPMOST);
            //KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
			SetSystemPowerState(NULL, POWER_STATE_RESET, POWER_FORCE);
            
            DestroyWindow(hDlg);
        }
        
        break;
        
    case WM_COMMAND:
        
        switch( LOWORD( wParam ) ) {
        case IDC_SERVER :
            if (EN_KILLFOCUS == HIWORD(wParam)) {
                GetWindowText (GetDlgItem (hDlg, IDC_SERVER), v_szServerName,
                               sizeof(v_szServerName)/sizeof(TCHAR));
                hThread = CreateThread (NULL, 0, FTPFillComboBox, 0, 0, &dwThreadID);
                CloseHandle (hThread);
            }
            break;
        case IDC_SOURCENAME :
            GetWindowText (GetDlgItem (hDlg, IDC_SOURCENAME), v_szSourceName,
                           sizeof(v_szSourceName)/sizeof(TCHAR));
            // If they just moved off the field and the name includes a wildcard then populate the box
            if ((CBN_KILLFOCUS == HIWORD(wParam)) && _tcschr (v_szSourceName, L'*')) {
                // Refill the box
                _tcscpy (v_szPathSpec, v_szSourceName);
                hThread = CreateThread (NULL, 0, FTPFillComboBox, 0, 0, &dwThreadID);
                CloseHandle (hThread);
            }
            break;
        case IDC_APPLY :
            GetWindowText (GetDlgItem (hDlg, IDC_SERVER), v_szServerName,
                           sizeof(v_szServerName)/sizeof(TCHAR));
            GetWindowText (GetDlgItem (hDlg, IDC_SOURCENAME), v_szSourceName,
                           sizeof(v_szSourceName)/sizeof(TCHAR));
            GetWindowText (GetDlgItem (hDlg, IDC_DESTNAME), v_szFinalName,
                           sizeof(v_szFinalName)/sizeof(TCHAR));

            _tcscpy (szTemp, v_szFinalName);
            for (i=_tcslen(szTemp); i >= 0; i--) {
                if (TEXT('\\') == szTemp[i]) {
                    szTemp[i] = TEXT('\0');
                    break;
                }
            }

            // Try to delete the old temp file, ignore errors if it doesn't exist
            _tcscpy (v_szTempName, v_szFinalName);
            _tcscat (v_szTempName, TEXT(".new"));
            DeleteFile (v_szTempName);

            RETAILMSG (ZONE_WARN, (TEXT("About to call GetDiskFreeSpace on '%s'\r\n"), szTemp));
            while (!GetDiskFreeSpaceEx (szTemp, &uliFreeBytes, &uliTotalBytes, &uliTotalFree)) {
                // Did we get an error on root too?
                if (TEXT('\0') == szTemp[0]) {
                    ShowError (IDS_ERR_GETDISKFREESPACE, GetLastError());
                    break;
                }
                
                // Remove another subdir from the name.
                for (i=_tcslen(szTemp); i >= 0; i--) {
                    if (TEXT('\\') == szTemp[i]) {
                        szTemp[i] = TEXT('\0');
                        break;
                    }
                }
                RETAILMSG (ZONE_WARN, (TEXT("Trying new path='%s'\r\n"), szTemp));
            }
            
            dwImageSize = FTPGetFileSize ();
            RETAILMSG (1, (TEXT("DiskFreeSpace(%s) Free=%d, ImageSize=%d\r\n"), szTemp,
                           uliFreeBytes.LowPart, dwImageSize));
            _tcscpy (v_szTempName, v_szFinalName);
            if (dwImageSize > uliFreeBytes.LowPart) {
                // Not enough room to get a temp copy, ask the user?
                if (IDYES != MessageBox (hDlg, TEXT("Not enough room to get a temp copy, continue?"), v_szAppName,
                                         MB_YESNO|MB_ICONEXCLAMATION|MB_TOPMOST)) {
                    // Chicken....
                    break;
                }
            } else {
                _tcscat (v_szTempName, TEXT(".new"));
            }

            // Ok, now we actually do the download.
            hThread = CreateThread (NULL, 0, FTPGetFile, 0, 0, &dwThreadID);
            CloseHandle (hThread);

            dwStartTick = GetTickCount();

            // TODO: Disable some dialog buttons during the download?
            break;
        case IDCANCEL :
            RETAILMSG (1, (TEXT("Got IDCANCEL\r\n")));
            DestroyWindow(hDlg);
            break;
        case IDC_ABOUT :
            DoFmtMsg (IDS_STR_ABOUT, szTemp, sizeof(szTemp)/sizeof(TCHAR), CE_MAJOR_VER, CE_MINOR_VER);
            MessageBox (v_hMainWnd, szTemp, v_szAppName, MB_OK | MB_TOPMOST);
            break;
        }
        break;
    case WM_DESTROY :
        PostQuitMessage(0);
        break;
    default:
		break;
	}
	return (0);
}


BOOL
InitInstance(int nCmdShow)
{
    v_hMainWnd = CreateDialog(v_hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);

    if (v_hMainWnd) {
        UpdateWindow(v_hMainWnd);
    }

    return (NULL != v_hMainWnd);
}

void GetRegSettings()
{
    HKEY    hKey;
    LONG    hRes;
    DWORD   dwSize;

	hRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, FTPUPDATE_REG_KEY, 0, KEY_READ, &hKey);

    if (ERROR_SUCCESS == hRes) {
        dwSize = sizeof(v_szServerName);
        RegQueryValueEx (hKey, FTPUPDATE_SRV_VAL, 0, NULL, (LPBYTE)v_szServerName, &dwSize);
        dwSize = sizeof(v_szPathSpec);
        RegQueryValueEx (hKey, FTPUPDATE_PATH_VAL, 0, NULL, (LPBYTE)v_szPathSpec, &dwSize);
        dwSize = sizeof(v_szSourceName);
        RegQueryValueEx (hKey, FTPUPDATE_SRC_VAL, 0, NULL, (LPBYTE)v_szSourceName, &dwSize);
        dwSize = sizeof(v_szFinalName);
        RegQueryValueEx (hKey, FTPUPDATE_DEST_VAL, 0, NULL, (LPBYTE)v_szFinalName, &dwSize);
        dwSize = sizeof(v_dwFlags);
        RegQueryValueEx (hKey, FTPUPDATE_FLAGS_VAL, 0, NULL, (LPBYTE)&v_dwFlags, &dwSize);

        RegCloseKey (hKey);
    }


    RETAILMSG (ZONE_REG, (TEXT("FTPUpdate: ServerName='%s'\r\n"), v_szServerName));
    RETAILMSG (ZONE_REG, (TEXT("FTPUpdate: PathSpec='%s'\r\n"), v_szPathSpec));
    RETAILMSG (ZONE_REG, (TEXT("FTPUpdate: SourceName='%s'\r\n"), v_szSourceName));
    RETAILMSG (ZONE_REG, (TEXT("FTPUpdate: FinalName='%s'\r\n"), v_szFinalName));
    RETAILMSG (ZONE_REG, (TEXT("FTPUpdate: dwFlags='0x%08X'\r\n"), v_dwFlags));
    
    return;
}
    


int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPWSTR pszCmdLine,
	 int nCmdShow)
{
    MSG msg;

	v_hInstance = hInst;


    if (FALSE == GetWinInetFuncs()) {
        ShowError (IDS_ERR_INTERNET_OPEN, GetLastError());
        return -1;
    }
    
    LoadString (v_hInstance, IDS_APPNAME, v_szAppName,
                sizeof(v_szAppName)/sizeof(TCHAR));
    
    InitCommonControls();

    GetRegSettings();

	if (!InitInstance (nCmdShow)) {
        RETAILMSG (1, (TEXT("Error from InitInstance\r\n")));
		if (v_hMainWnd) {
			DestroyWindow(v_hMainWnd);
		}
		goto ExitMain;
	}

    while ( GetMessage(&msg, NULL, 0, 0) != FALSE ) {
        if (v_hMainWnd == 0 || !IsDialogMessage(v_hMainWnd, &msg)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

ExitMain:
    return 0;
}
